package com.nulldev.util.networking.npacket4.extensions.security;

import static com.nulldev.util.networking.npacket4.util.nPacketUtil.__readInt;

import java.io.ByteArrayOutputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStream;

import com.nulldev.util.networking.npacket4.extensions.PacketExtension;
import com.nulldev.util.networking.npacket4.extensions.PacketExtensions;

/**
 * SEC: The Secure Communication Packet. <br>
 * Data Layout: <br>
 * <code>EXT_ID | EXT_CIPHER (String) | EXT_DATA_LENGTH (int) | EXT_DATA (byte[]) </code>
 * <br>
 * Accepted ciphers: <br>
 * <ul>
 * <li>AES-128</li>
 * </ul>
 * 
 * @author null
 * @since 3.0
 */
public class SecureCommunicationExtension implements PacketExtension {
	private static final long serialVersionUID = 7162983550653178549L;

	private volatile String cipher;
	private volatile byte[] key;
	private PacketSecurer sec;

	public SecureCommunicationExtension(final String cipher, final byte[] key) {
		this.cipher = cipher;
		this.key = key;
	}

	public SecureCommunicationExtension(final String cipher, final PacketSecurer sec) {
		this.cipher = cipher;
		this.sec = sec;
		this.key = sec.getKey();
	}

	public SecureCommunicationExtension(final PacketSecurer sec) {
		this.cipher = sec.cipher();
		this.sec = sec;
		this.key = sec.getKey();
	}

	@Override
	public int extensionID() {
		return PacketExtensions.PacketExtensionID.EXT_ENCRYPTED;
	}

	@Override
	public byte[] extensionData() {
		final ByteArrayOutputStream baos = new ByteArrayOutputStream();
		final DataOutputStream dos = new DataOutputStream(baos);
		try {
			dos.writeInt(this.extensionID());
			dos.flush();
			dos.writeInt(this.cipher.length());
			dos.flush();
			dos.write(this.cipher.getBytes());
			dos.flush();
			dos.writeInt(this.key.length);
			dos.flush();
			dos.write(this.key);
		} catch (IOException e2) {
			throw new RuntimeException("extensionData() -> Failed to write extension data.", e2);
		}
		try {
			dos.flush();
			baos.flush();
		} catch (IOException e1) {
		}
		final byte[] data = baos.toByteArray();
		try {
			baos.close();
		} catch (IOException e) {
		}
		return data;
	}

	public String getCipher() {
		return this.cipher;
	}

	public byte[] getKey() {
		return this.key;
	}

	public PacketSecurer securer() {
		return this.sec;
	}

	@Override
	public byte[] processData(final byte[] data) {
		if (this.sec != null) {
			return this.sec.decrypt(data);
		} else {
			return data;
		}
	}

	@Override
	public SecureCommunicationExtension readExtensionData(final InputStream dis) throws IOException {
		final int cipher_name_length = __readInt(dis);
		byte[] cipher = new byte[cipher_name_length];
		dis.read(cipher);
		this.cipher = new String(cipher);
		final int keyLength = __readInt(dis);
		byte[] key = new byte[keyLength];
		dis.read(key);
		this.key = key;
		return this;
	}
}
